package cn.rocky.pandacodegen.service;

import cn.rocky.pandacodegen.common.config.GeneratorConfig;
import cn.rocky.pandacodegen.common.utils.SqlHelper;
import cn.rocky.pandacodegen.domain.definition.ColumnDefinition;
import cn.rocky.pandacodegen.domain.definition.JavaColumnDefinition;
import cn.rocky.pandacodegen.domain.vo.TableDefinition;
import cn.rocky.pandacodegen.database.mysqlfolder.MySqlColumnSelector;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;


@AllArgsConstructor
@Data
public abstract class TableSelector {


    /**
     * 列选择器
     */
    private ColumnSelector columnSelector;

    /**
     * 配置
     */
    private GeneratorConfig generatorConfig;

    /**
     * 表名
     */
    private List<String> schTableNames;

    /**
     * 表选择器
     *
     * @param mySqlColumnSelector sql列选择器
     * @param generatorConfig     配置
     */
    public TableSelector(MySqlColumnSelector mySqlColumnSelector, GeneratorConfig generatorConfig) {
        this.generatorConfig = generatorConfig;
        this.columnSelector = mySqlColumnSelector;
    }

    /**
     * 查询数据库表的SQL
     *
     * mysql 传入数据库名
     * @param generatorConfig 配置
     * @return 返回获取表信息的sql
     */
    protected abstract String getShowTablesSQL(GeneratorConfig generatorConfig);

    protected abstract TableDefinition buildTableDefinition(Map<String, Object> tableMap);

    public List<TableDefinition> getTableDefinitions() {
        List<Map<String, Object>> resultList = SqlHelper.runSql(getGeneratorConfig(), getShowTablesSQL(generatorConfig));
        List<TableDefinition> tablesList = new ArrayList<>(resultList.size());

        for (Map<String, Object> rowMap : resultList) {
            TableDefinition tableDefinition = this.buildTableDefinition(rowMap);
            String tableName = tableDefinition.getTableName();
            List<ColumnDefinition> columnDefinitions = columnSelector.getColumnDefinitions(tableName);
            tableDefinition.setColumnDefinitions(buildRealColumnDefinitions(columnDefinitions, JavaColumnDefinition::new));
            tablesList.add(tableDefinition);
        }

        return tablesList;
    }

    private <T> List<T> buildRealColumnDefinitions(List<ColumnDefinition> columnDefinitions, Supplier<T> supplier) {
        return columnDefinitions.stream()
                .map(columnDefinition -> {
                    T t = supplier.get();
                    BeanUtils.copyProperties(columnDefinition, t);
                    return t;
                })
                .collect(Collectors.toList());
    }
}
